package com.liugh.fastDFS;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerGroup;
import org.csource.fastdfs.TrackerServer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class ConnectionPool {

    private static final Log log = LogFactory.get();

    //繁忙的连接实例
    private ConcurrentHashMap<StorageClient1, Object> busyConnectionPool;
    //空闲连接实例
    private ArrayBlockingQueue<StorageClient1> idleConnectionPool;

    private final int port = 22122;

    private final String trackServer = "47.105.140.28";

    //连接实例的限制
    private final int size = 10;

    private Object obj = new Object();

    //singleton
    private ConnectionPool() {
        busyConnectionPool = new ConcurrentHashMap<>();
        idleConnectionPool = new ArrayBlockingQueue<>(size);
        init();
    }

    private static ConnectionPool instance = new ConnectionPool();

    //获取连接池实例
    static ConnectionPool getPoolInstance() {
        return instance;
    }

    //初始化连接池
    private void init() {
        initClientGlobal();
        TrackerServer trackerServer = null;
        try {
            TrackerClient trackerClient = new TrackerClient();
            // Only tracker
            trackerServer = trackerClient.getConnection();
            for (int i = 0; i < size; i++) {
                StorageClient1 client1 = new StorageClient1(trackerServer, null);
                idleConnectionPool.add(client1);
            }
            log.info("初始化连接池成功，现在有 " + size + "个连接");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (trackerServer != null) {
                try {
                    trackerServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 1. 从idleConnectionPool弹出一个连接，
    // 2. 将连接推入busyConnectionPool;
    // 3. 返回连接
    // 4. 如果没有空闲连接，请等待wait_time秒，然后再次检查
    StorageClient1 checkout() throws InterruptedException {
        StorageClient1 client1 = idleConnectionPool.poll(10, TimeUnit.SECONDS);
        assert client1 != null;
        busyConnectionPool.put(client1, obj);
        return client1;
    }

    // 1. 从busyConnectionPool弹出连接;
    // 2. 将连接推入idleConnectionPool;
    // 3. 做必要的清理工作。
    void checkin(StorageClient1 client1) {
        if (busyConnectionPool.remove(client1) != null) {
            idleConnectionPool.add(client1);
        }
    }

    // 所以如果连接因某些错误而中断（比如:套接字初始化失败，网络中断等），请删除此连接
    // 从busyConnectionPool，并初始化一个新的连接。
    void drop(StorageClient1 client1) {
        if (busyConnectionPool.remove(client1) != null) {
            TrackerServer trackerServer = null;
            try {
                TrackerClient trackerClient = new TrackerClient();
                trackerServer = trackerClient.getConnection();
                StorageClient1 newClient1 = new StorageClient1(trackerServer, null);
                idleConnectionPool.add(newClient1);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (trackerServer != null) {
                    try {
                        trackerServer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private void initClientGlobal() {
        InetSocketAddress[] trackerServers = new InetSocketAddress[1];
        trackerServers[0] = new InetSocketAddress(trackServer, port);
        ClientGlobal.setG_tracker_group(new TrackerGroup(trackerServers));
        // 连接超时的时限，单位为毫秒
        ClientGlobal.setG_connect_timeout(2000);
        // 网络超时的时限，单位为毫秒
        ClientGlobal.setG_network_timeout(30000);
        ClientGlobal.setG_anti_steal_token(false);
        // 字符集
        ClientGlobal.setG_charset("UTF-8");
        ClientGlobal.setG_secret_key(null);
    }
}